home *** CD-ROM | disk | FTP | other *** search
/ Reverse Code Engineering RCE CD +sandman 2000 / ReverseCodeEngineeringRceCdsandman2000.iso / RCE / Library / Manuels & Misc / Assembly / AOA.ZIP / CH09 / PGM9_3.ASM < prev    next >
Encoding:
Assembly Source File  |  1996-02-08  |  4.5 KB  |  229 lines

  1. ; Pgm9_3.ASM
  2. ;
  3. ; This sample program provides two procedures that read and write
  4. ; 64-bit unsigned integer values on an 80386 or later processor.
  5.  
  6.         .xlist
  7.         include     stdlib.a
  8.         includelib    stdlib.lib
  9.         .list
  10.  
  11.         .386
  12.         option    segment:use16
  13.  
  14. dp        textequ    <dword ptr>
  15. byp        textequ    <byte ptr>
  16.  
  17. dseg        segment    para public 'data'
  18.  
  19. ; Acc64 is a 64 bit value that the ATOU64 routine uses to input
  20. ; a 64-bit value.
  21.  
  22. Acc64        qword    0
  23.  
  24.  
  25.  
  26. ; Quotient holds the result of dividing the current PUTU value by
  27. ; ten.
  28.  
  29. Quotient    qword    0
  30.  
  31.  
  32. ; NumOut holds the string of digits created by the PUTU64 routine.
  33.  
  34. NumOut        byte    32 dup (0)
  35.  
  36.  
  37.  
  38. ; A sample test string for the ATOI64 routine:
  39.  
  40. LongNumber    byte    "123456789012345678",0
  41.  
  42.  
  43. dseg        ends
  44.  
  45. cseg        segment    para public 'code'
  46.         assume    cs:cseg, ds:dseg
  47.  
  48.  
  49. ; ATOU64-    On entry, ES:DI point at a string containing a
  50. ;        sequence of digits.  This routine converts that
  51. ;        string to a 64-bit integer and returns that
  52. ;        unsigned integer value in EDX:EAX.
  53. ;
  54. ;        This routine uses the algorithm:
  55. ;
  56. ;        Acc := 0
  57. ;        while digits left
  58. ;
  59. ;            Acc := (Acc * 10) + (Current Digit - '0')
  60. ;            Move on to next digit
  61. ;
  62. ;        endwhile
  63.  
  64.  
  65. ATOU64        proc    near
  66.         push    di        ;Save because we modify it.
  67.         mov    dp Acc64, 0    ;Initialize our accumulator.
  68.         mov    dp Acc64+4, 0
  69.  
  70. ; While we've got some decimal digits, process the input string:
  71.  
  72.         sub    eax, eax    ;Zero out eax's H.O. 3 bytes.
  73. WhileDigits:    mov    al, es:[di]
  74.         xor    al, '0'        ;Translates '0'..'9' -> 0..9
  75.         cmp    al, 10        ; and everything else is > 9.
  76.         ja    NotADigit
  77.  
  78. ; Multiply Acc64 by ten.  Use shifts and adds to accomplish this:
  79.  
  80.         shl    dp Acc64, 1    ;Compute Acc64*2
  81.         rcl    dp Acc64+4, 1
  82.  
  83.         push    dp Acc64+4    ;Save Acc64*2
  84.         push    dp Acc64
  85.  
  86.         shl    dp Acc64, 1    ;Compute Acc64*4
  87.         rcl    dp Acc64+4, 1
  88.         shl    dp Acc64, 1    ;Compute Acc64*8
  89.         rcl    dp Acc64+4, 1
  90.  
  91.         pop    edx        ;Compute Acc64*10 as
  92.         add    dp Acc64, edx    ; Acc64*2 + Acc64*8
  93.         pop    edx
  94.         adc    dp Acc64+4, edx
  95.  
  96. ; Add in the numeric equivalent of the current digit.
  97. ; Remember, the H.O. three words of eax contain zero.
  98.  
  99.         add    dp Acc64, eax    ;Add in this digit
  100.  
  101.         inc    di        ;Move on to next char.
  102.         jmp    WhileDigits    ;Repeat for all digits.
  103.  
  104. ; Okay, return the 64-bit integer value in eax.
  105.  
  106. NotADigit:    mov    eax, dp Acc64
  107.         mov    edx, dp Acc64+4
  108.         pop    di
  109.         ret
  110. ATOU64        endp
  111.  
  112.  
  113.  
  114.  
  115.  
  116.  
  117. ; PUTU64-    On entry, EDX:EAX contain a 64-bit unsigned value.
  118. ;        Output a string of decimal digits providing the
  119. ;        decimal representation of that value.
  120. ;
  121. ;        This code uses the following algorithm:
  122. ;
  123. ;            di := 30;
  124. ;            while edx:eax <> 0 do
  125. ;
  126. ;                       OutputNumber[di] := digit;
  127. ;            edx:eax := edx:eax div 10
  128. ;            di := di - 1;
  129. ;
  130. ;            endwhile
  131. ;            Output digits from OutNumber[di+1]
  132. ;            through OutputNumber[30]
  133.  
  134. PUTU64        proc
  135.         push    es
  136.         push    eax
  137.         push    ecx
  138.         push    edx
  139.         push    di
  140.         pushf
  141.  
  142.  
  143.  
  144.         mov    di, dseg    ;This is where the output
  145.         mov    es, di        ; string will go.
  146.         lea    di, NumOut+30    ;Store characters in string
  147.         std            ; backwards.
  148.         mov    byp es:[di+1],0    ;Output zero terminating byte.
  149.  
  150.  
  151. ; Save the value to print so we can divide it by ten using an
  152. ; extended precision division operation.
  153.  
  154.         mov    dp Quotient, eax
  155.         mov    dp Quotient+4, edx
  156.  
  157.  
  158. ; Okay, begin converting the number into a string of digits.
  159.  
  160.         mov    ecx, 10            ;Value to divide by.
  161. DivideLoop:    mov    eax, dp Quotient+4    ;Do a 64-bit by
  162.         sub    edx, edx        ; 32-bit division
  163.         div    ecx                     ; (see the text
  164.         mov    dp Quotient+4, eax    ;  for details).
  165.  
  166.         mov    eax, dp Quotient
  167.         div    ecx
  168.         mov    dp Quotient, eax
  169.  
  170. ; At this time edx (dl, actually) contains the remainder of the
  171. ; above division by ten, so dl is in the range 0..9.  Convert
  172. ; this to an ASCII character and save it away.
  173.  
  174.         mov    al, dl
  175.         or    al, '0'
  176.         stosb
  177.  
  178. ; Now check to see if the result is zero.  When it is, we can
  179. ; quit.
  180.  
  181.         mov    eax, dp Quotient
  182.         or    eax, dp Quotient+4
  183.         jnz    DivideLoop
  184.  
  185. OutputNumber:    inc    di
  186.         puts
  187.         popf
  188.         pop    di
  189.         pop    edx
  190.         pop    ecx
  191.         pop    eax
  192.         pop    es
  193.         ret
  194. PUTU64        endp
  195.  
  196.  
  197.  
  198. ; The main program provides a simple test of the two routines
  199. ; above.
  200.  
  201. Main        proc
  202.         mov    ax, dseg
  203.         mov    ds, ax
  204.         mov    es, ax
  205.         meminit
  206.  
  207.         lesi    LongNumber
  208.         call    ATOU64
  209.         call    PutU64
  210.         printf
  211.         byte    cr,lf
  212.         byte    "%x %x %x %x",cr,lf,0
  213.         dword    Acc64+6, Acc64+4, Acc64+2, Acc64
  214.  
  215.  
  216. Quit:        ExitPgm            ;DOS macro to quit program.
  217. Main        endp
  218.  
  219. cseg        ends
  220.  
  221. sseg        segment    para stack 'stack'
  222. stk        byte    1024 dup ("stack   ")
  223. sseg        ends
  224.  
  225. zzzzzzseg    segment    para public 'zzzzzz'
  226. LastBytes    byte    16 dup (?)
  227. zzzzzzseg    ends
  228.         end    Main
  229.